package com.gusto.engine.colfil.service.util;

import java.util.List;

import org.apache.log4j.Logger;

import com.gusto.engine.colfil.Distance;
import com.gusto.engine.colfil.Rating;
import com.gusto.engine.colfil.formula.ItemCorrelation;
import com.gusto.engine.colfil.formula.UserCorrelation;
import com.gusto.engine.colfil.matrix.MatrixDAO;
import com.gusto.engine.colfil.transformation.Transformation;

/**
 * <p>Uses an evaluation matrix {@link MatrixDAO} to get the ratings,
 * a {@link UserCorrelation} and a {@link ItemCorrelation} to calculate the distances,
 * after the application of a number of {@link Transformation}.</p>
 * 
 * @author amokrane.belloui@gmail.com
 */
public class DistanceCalculator {
	
	private Logger log = Logger.getLogger(getClass());
	
	// TODO consider Predictions or no
	// TODO Adding transformations
	
	private MatrixDAO matrixDAO;
	private UserCorrelation userCorrelation;
	private ItemCorrelation itemCorrelation;
	
	public DistanceCalculator() {
		super();
	}
	
	public void setMatrixDAO(MatrixDAO matrixDAO) {
		this.matrixDAO = matrixDAO;
	}
	
	public void setUserCorrelation(UserCorrelation userCorrelation) {
		this.userCorrelation = userCorrelation;
	}

	public void setItemCorrelation(ItemCorrelation itemCorrelation) {
		this.itemCorrelation = itemCorrelation;
	}
	
	public Distance calculateUserDistance(long user1, long user2) {
		log.debug("Calculating Distance between Users " + user1 + " " + user2);
		List<Rating> evals1 = matrixDAO.getItemsRatedByUser(user1, false);
		List<Rating> evals2 = matrixDAO.getItemsRatedByUser(user2, false);
		// - Consider Predictions or no
		
		// Process Difference between users
		// - Add Transformation
		// - Correlation Algorithm
		// - Consider Predictions or no
		
		Distance d = userCorrelation.userCorrelation(user1, user2, evals1, evals2);
		log.info("Distance between Users " + user1 + " " + user2);
		return d;
	}
	
	public Distance calculateItemDistance(long item1, long item2) {
		log.debug("Calculating Distance between Items " + item1 + " " + item2);
		List<Rating> evals1 = matrixDAO.getUsersHavingRatedItem(item1, false);
		List<Rating> evals2 = matrixDAO.getUsersHavingRatedItem(item2, false);
		// - Consider Predictions or no
		
		// Process Difference between users
		// - Add Transformation
		// - Correlation Algorithm
		// - Consider Predictions or no
		
		Distance d = itemCorrelation.itemCorrelation(item1, item2, evals1, evals2);
		log.info("Distance between Items " + item1 + " " + item2);
		return d;
	}

	
}
